package com.esb.transport.protocal;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.esb.stereotype.Service;

public class ServiceDispatcher {
	private final static Map<String, Object> serviceMap = new ConcurrentHashMap<String, Object>();
	
	public static void register(Object service){
		if(service==null)throw new RuntimeException("不能导出空服务!");
		if(serviceMap.containsKey(service.getClass().getInterfaces())){
			throw new RuntimeException("已存在相同服务!");
		}
		String serviceName = getServiceName(service.getClass());
		
		if(serviceName==null)throw new RuntimeException("对象未用Service注解为服务!");
		serviceMap.put(serviceName, service);
	}
	
	public static String getServiceName(Class<?> clazz){
		if(clazz.isInterface()){
			Class<?> c = clazz;
			while(c!=null){
				Service s = c.getAnnotation(Service.class);
				if(s!=null){
					return s.value() + s.version();
				}
				c = c.getSuperclass();
			}
		}else{
			for(Class<?> c:clazz.getInterfaces()) {
				while(c!=null){
					Service s = c.getAnnotation(Service.class);
					if(s!=null){
						return s.value() + s.version();
					}
					c = c.getSuperclass();
				}
			}
		}
		return null;
	}

	public static Object dispatch(Request req){//String serviceName, String methodName, Object... args){
		Object service = serviceMap.get(req.getServiceName());
		if(service==null)return null;
		for(Method m:service.getClass().getMethods()){
			if(m.getName().equalsIgnoreCase(req.getMethodName()) && judge(m, req.getArguments())){
				try {
					return m.invoke(service, req.getArguments());
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			}
		}
		return null;
	}
	
	private static boolean judge(Method m, Object... args){
		Class<?>[] types = m.getParameterTypes();
		if(types.length==args.length){
			for(int i=0;i<args.length;i++){
				if (types[i].isAssignableFrom(args[i].getClass())==false) {
					return false;
				}
			}
		}
		return true;
	}
}
